import 'dart:math';

import 'package:flutter/material.dart';

import 'color_box.dart';

class PackBoxWrapper extends StatelessWidget {
  final animateKey = GlobalKey<PackBoxState>();
  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.bottomCenter,
      children: [
        PackBox(
          key: animateKey,
        ),
        Positioned(
          child: TextButton(
            onPressed: () {
              animateKey.currentState!.pack();
            },
            child: Icon(Icons.flip),
          ),
          bottom: 30,
          width: 40,
          height: 40,
        ),
      ],
    );
  }
}

class PackBox extends StatefulWidget {
  PackBox({Key? key}) : super(key: key);

  @override
  PackBoxState createState() => PackBoxState();
}

class PackBoxState extends State<PackBox> with TickerProviderStateMixin {
  late AnimationController _controller;
  late CurvedAnimation _curve;
  bool _pack = true;

  @override
  void initState() {
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 500),
    );
    _controller.addStatusListener(_updateStatus);
    _curve =
        new CurvedAnimation(parent: _controller, curve: Curves.easeInOutSine);
    super.initState();
  }

  void _updateStatus(AnimationStatus status) {
    if (status == AnimationStatus.completed ||
        status == AnimationStatus.dismissed) {
      setState(() {
        _pack = !_pack;
      });
    }
  }

  void pack() {
    if (_pack) {
      _controller.forward();
    } else {
      _controller.reverse();
    }
  }

  @override
  void dispose() {
    _controller.removeStatusListener(_updateStatus);
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            PackAnimationBuilder(
              builder: (context) => ColorBox(
                width: 80,
                height: 80,
                color: Colors.pink[400]!,
              ),
              animation: _controller,
              entryAngle: -0.003,
              stopAngle: 0.0,
              maxAngle: pi / 2,
              rotationAxis: RotationAxis.x,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                PackAnimationBuilder(
                  builder: (context) => ColorBox(
                    width: 80,
                    height: 80,
                    color: Colors.red[400]!,
                  ),
                  animation: _controller,
                  entryAngle: -0.005,
                  stopAngle: 0.0,
                  maxAngle: pi / 2,
                  rotationAxis: RotationAxis.y,
                ),
                ColorBox(
                  width: 80,
                  height: 80,
                  color: Colors.green[400]!,
                ),
                PackAnimationBuilder(
                  builder: (context) => ColorBox(
                    width: 80,
                    height: 80,
                    color: Colors.blue[400]!,
                  ),
                  animation: _curve,
                  entryAngle: 0.005,
                  stopAngle: 0,
                  maxAngle: pi / 2,
                  rotationAxis: RotationAxis.y,
                ),
              ],
            ),
            PackAnimationBuilder(
              builder: (context) => ColorBox(
                width: 80,
                height: 80,
                color: Colors.orange[400]!,
              ),
              animation: _controller,
              entryAngle: 0.01,
              stopAngle: 0.00,
              maxAngle: pi / 2,
              rotationAxis: RotationAxis.x,
            ),
          ],
        ),
      ),
    );
  }
}

enum RotationAxis { x, y, z }

class PackAnimationBuilder extends StatelessWidget {
  final Animation<double> animation;
  final WidgetBuilder builder;
  final double entryAngle;
  final double stopAngle;
  final RotationAxis rotationAxis;
  final double maxAngle;
  PackAnimationBuilder(
      {required this.animation,
      required this.entryAngle,
      required this.stopAngle,
      required this.maxAngle,
      required this.builder,
      required this.rotationAxis,
      Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: animation,
        builder: (context, widget) {
          bool pack = animation.value < 1.0;
          final child = builder(context);
          double rotationAngle = animation.value * maxAngle - stopAngle;
          var tilt = (animation.value - 1).abs() - 1;
          //设置一个小的偏移量，使得旋转时有一定的倾斜角度，看起来更有立体感
          tilt *= pack ? -entryAngle : entryAngle;
          Alignment alignment =
              entryAngle > 0 ? Alignment.centerRight : Alignment.centerLeft;
          Matrix4 transform;
          switch (rotationAxis) {
            case RotationAxis.x:
              transform = Matrix4.rotationX(rotationAngle)
                ..setEntry(3, 1, tilt);
              alignment =
                  entryAngle > 0 ? Alignment.topCenter : Alignment.bottomCenter;
              break;
            case RotationAxis.y:
              transform = Matrix4.rotationY(rotationAngle)
                ..setEntry(3, 0, tilt);
              alignment =
                  entryAngle > 0 ? Alignment.centerLeft : Alignment.centerRight;
              break;
            case RotationAxis.z:
              transform = Matrix4.rotationZ(rotationAngle)
                ..setEntry(3, 0, tilt);
              break;
          }
          return Transform(
            transform: transform,
            child: child,
            alignment: alignment,
          );
        });
  }
}
